{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 比较器（Comparator）及其在 Collection 和 Array 中的应用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在计算机科学中，**排序**和**比较**是数据处理的核心操作之一。无论是对数据进行排序、查找还是过滤，都需要一种机制来确定元素之间的相对顺序。Java 提供了强大的工具来实现这一功能，其中之一就是 Comparator 接口。**本文档旨在详细记录 Comparator 在 Java 中的应用，特别是它在集合（如 Set, List, Map）和数组中的使用方法。**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 定义\n",
    "Comparator 是一个接口，定义了如何比较两个对象的顺序。它通常用于需要自定义排序规则的场合，尤其是在集合类（如 List 和 Set）中。Comparator 接口只有一个方法 compare(T o1, T o2)，用于比较两个对象 o1 和 o2 的顺序。  \n",
    "下面是 Comparator 接口的基本定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public interface Comparator<T> {\n",
    "    int compare(T o1, T o2);\n",
    "    boolean equals(Object obj);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "notebookRunGroups": {
     "groupValue": "1"
    }
   },
   "source": [
    "### **方法详解**  \n",
    "**compare(T o1, T o2)**：此方法用于比较两个对象 o1 和 o2 的顺序。返回值的含义如下：  \n",
    "- 如果 o1 小于 o2，则返回负整数，表明第一个对象应该排在第二个对象之前；\n",
    "- 如果 o1 等于 o2，则返回零，则表明两个对象相等；\n",
    "- 如果 o1 大于 o2，则返回正整数，则表明第一个对象应该排在第二个对象之后。  \n",
    "\n",
    "**equals(Object obj)**：此方法是从 Object 类继承来的，并不是 Comparator 接口的一部分。它用于判断两个比较器是否等价，即它们是否会产生相同的排序结果。\n",
    "\n",
    "### **实现原理**\n",
    "Comparator 接口的主要作用是在集合操作中提供一种外部排序机制。通常，集合框架中的排序操作会调用比较器的 compare 方法来确定元素之间的相对顺序。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 常用的 `Comparator` 静态工厂方法\n",
    "\n",
    "1. **`comparing(Function<T, U> keyExtractor)`**：\n",
    "   - 根据提供的 `keyExtractor` 函数来提取键进行比较。\n",
    "\n",
    "2. **`comparingInt(Function<T, Integer> keyExtractor)`**：\n",
    "   - 根据提供的 `keyExtractor` 函数提取 `int` 类型的键进行比较。\n",
    "\n",
    "3. **`comparingLong(Function<T, Long> keyExtractor)`**：\n",
    "   - 根据提供的 `keyExtractor` 函数提取 `long` 类型的键进行比较。\n",
    "\n",
    "4. **`comparingDouble(Function<T, Double> keyExtractor)`**：\n",
    "   - 根据提供的 `keyExtractor` 函数提取 `double` 类型的键进行比较。\n",
    "\n",
    "5. **`naturalOrder()`**：\n",
    "   - 返回一个自然顺序的比较器，适用于实现了 `Comparable` 接口的类型。\n",
    "\n",
    "6. **`reversedOrder()`**：\n",
    "   - 返回一个逆序的比较器，适用于实现了 `Comparable` 接口的类型。\n",
    "\n",
    "7. **`reversed()`**：\n",
    "   - 反转现有的比较器。\n",
    "\n",
    "8. **`thenComparing(Comparator<? super T> other)`**：\n",
    "   - 在当前比较器的基础上添加另一个比较器作为次级比较器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "// 定义 Person 类\n",
    "public class Person {\n",
    "    private String name;\n",
    "    private int age;\n",
    "\n",
    "    public Person(String name, int age) {\n",
    "        this.name = name;\n",
    "        this.age = age;\n",
    "    }\n",
    "\n",
    "    public String getName() {\n",
    "        return name;\n",
    "    }\n",
    "\n",
    "    public int getAge() {\n",
    "        return age;\n",
    "    }\n",
    "\n",
    "    @Override\n",
    "    public String toString() {\n",
    "        return \"Person{\" +\n",
    "                \"name='\" + name + '\\'' +\n",
    "                \", age=\" + age +\n",
    "                '}';\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original list: \n",
      "[Person{name='Alice', age=30}, Person{name='Bob', age=25}, Person{name='Charlie', age=35}, Person{name='David', age=30}]\n",
      "Sorted by age ascending: \n",
      "[Person{name='Bob', age=25}, Person{name='Alice', age=30}, Person{name='David', age=30}, Person{name='Charlie', age=35}]\n",
      "Sorted by age descending: \n",
      "[Person{name='Charlie', age=35}, Person{name='Alice', age=30}, Person{name='David', age=30}, Person{name='Bob', age=25}]\n",
      "Sorted by age then name: \n",
      "[Person{name='Bob', age=25}, Person{name='Alice', age=30}, Person{name='David', age=30}, Person{name='Charlie', age=35}]\n",
      "Sorted by name natural order: \n",
      "[Person{name='Alice', age=30}, Person{name='Bob', age=25}, Person{name='Charlie', age=35}, Person{name='David', age=30}]\n",
      "Sorted by name reversed order: \n",
      "[Person{name='David', age=30}, Person{name='Charlie', age=35}, Person{name='Bob', age=25}, Person{name='Alice', age=30}]\n"
     ]
    }
   ],
   "source": [
    "import java.util.Arrays;\n",
    "import java.util.Comparator;\n",
    "import java.util.List;\n",
    "import java.util.stream.Collectors;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        List<Person> people = Arrays.asList(\n",
    "            new Person(\"Alice\", 30),\n",
    "            new Person(\"Bob\", 25),\n",
    "            new Person(\"Charlie\", 35),\n",
    "            new Person(\"David\", 30)\n",
    "        );\n",
    "\n",
    "        // 创建升序比较器（按年龄）\n",
    "        Comparator<Person> byAgeAscending = Comparator.comparingInt(Person::getAge);\n",
    "\n",
    "        // 创建降序比较器（按年龄）\n",
    "        Comparator<Person> byAgeDescending = byAgeAscending.reversed();\n",
    "\n",
    "        // 创建多条件比较器（先按年龄升序，再按名字升序）\n",
    "        Comparator<Person> byAgeThenName = Comparator.comparingInt(Person::getAge)\n",
    "                                                    .thenComparing(Comparator.comparing(Person::getName));\n",
    "\n",
    "        // 创建自然顺序比较器（按名字）\n",
    "        Comparator<Person> byNameNaturalOrder = Comparator.comparing(Person::getName);\n",
    "\n",
    "        // 创建逆序比较器（按名字）\n",
    "        Comparator<Person> byNameReversedOrder = byNameNaturalOrder.reversed();\n",
    "\n",
    "        // 使用升序比较器对列表进行排序\n",
    "        List<Person> sortedByAgeAscending = people.stream()\n",
    "                                                  .sorted(byAgeAscending)\n",
    "                                                  .collect(Collectors.toList());\n",
    "\n",
    "        // 使用降序比较器对列表进行排序\n",
    "        List<Person> sortedByAgeDescending = people.stream()\n",
    "                                                   .sorted(byAgeDescending)\n",
    "                                                   .collect(Collectors.toList());\n",
    "\n",
    "        // 使用多条件比较器对列表进行排序\n",
    "        List<Person> sortedByAgeThenName = people.stream()\n",
    "                                                 .sorted(byAgeThenName)\n",
    "                                                 .collect(Collectors.toList());\n",
    "\n",
    "        // 使用自然顺序比较器对列表进行排序\n",
    "        List<Person> sortedByNameNaturalOrder = people.stream()\n",
    "                                                      .sorted(byNameNaturalOrder)\n",
    "                                                      .collect(Collectors.toList());\n",
    "\n",
    "        // 使用逆序比较器对列表进行排序\n",
    "        List<Person> sortedByNameReversedOrder = people.stream()\n",
    "                                                       .sorted(byNameReversedOrder)\n",
    "                                                       .collect(Collectors.toList());\n",
    "\n",
    "        // 打印排序结果\n",
    "        System.out.println(\"Original list: \\n\" + people);\n",
    "        System.out.println(\"Sorted by age ascending: \\n\" + sortedByAgeAscending);\n",
    "        System.out.println(\"Sorted by age descending: \\n\" + sortedByAgeDescending);\n",
    "        System.out.println(\"Sorted by age then name: \\n\" + sortedByAgeThenName);\n",
    "        System.out.println(\"Sorted by name natural order: \\n\" + sortedByNameNaturalOrder);\n",
    "        System.out.println(\"Sorted by name reversed order: \\n\" + sortedByNameReversedOrder);\n",
    "    }\n",
    "}\n",
    "\n",
    "Main.main(new String[] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **Comparator.comparingInt(Person::getAge)**：创建一个按年龄升序的比较器。\n",
    "- **byAgeAscending.reversed()**：创建一个按年龄降序的比较器。\n",
    "- **Comparator.comparingInt(Person::getAge).thenComparing(Comparator.comparing(Person::getName))**：创建一个多条件比较器，先按年龄升序，如果年龄相同则按名字升序。\n",
    "- **Comparator.comparing(Person::getName)**：创建一个按名字自然顺序的比较器。\n",
    "- **byNameNaturalOrder.reversed()**：创建一个按名字逆序的比较器。\n",
    "\n",
    "通过这些方法，您可以灵活地对 `Person` 对象列表进行各种排序操作。希望这能帮助您更好地理解和使用 `Comparator`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 注意事项\n",
    "\n",
    "- 当使用 `Comparator` 时，必须确保 `compare` 方法的实现是合理的，即它应该满足比较关系的传递性和对称性。\n",
    "- 如果 `Comparator` 比较的对象可能为 `null`，需要特别注意处理 `null` 值的情况。\n",
    "- 在多线程环境中使用 `Comparator` 时，应确保其线程安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 创建 Comparator 实例\n",
    "在 Java 中，可以通过实现 Comparator 接口来创建一个比较器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sorted array by age using anonymous inner class: \n",
      "Person{name='Bob', age=25}\n",
      "Person{name='Alice', age=30}\n",
      "Person{name='Charlie', age=35}\n"
     ]
    }
   ],
   "source": [
    "import java.util.Arrays;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        Person[] people = new Person[]{\n",
    "            new Person(\"Alice\", 30),\n",
    "            new Person(\"Bob\", 25),\n",
    "            new Person(\"Charlie\", 35)\n",
    "        };\n",
    "\n",
    "        // 使用自定义 Person 类定义 Comparator\n",
    "        Arrays.sort(people, new Comparator<Person>() {\n",
    "            @Override\n",
    "            public int compare(Person p1, Person p2) {\n",
    "                return Integer.compare(p1.getAge(), p2.getAge());\n",
    "            }\n",
    "        });\n",
    "\n",
    "        // 打印排序后的数组\n",
    "        System.out.println(\"Sorted array by age using anonymous inner class: \" );\n",
    "        for(Person temp:people){\n",
    "            System.out.println(temp.toString());\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "// [IJava] 调用main函数，查看 main()函数执行结果 在Jupyter notebook中的输出信息\n",
    "Main.main(new String [] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 Lambda 表达式\n",
    "从 Java 8 开始，可以使用 Lambda 表达式来简化 Comparator 的实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sorted array by age using anonymous inner class: \n",
      "Person{name='Bob', age=25}\n",
      "Person{name='Alice', age=30}\n",
      "Person{name='Charlie', age=35}\n"
     ]
    }
   ],
   "source": [
    "import java.util.Arrays;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        Person[] people = new Person[]{\n",
    "            new Person(\"Alice\", 30),\n",
    "            new Person(\"Bob\", 25),\n",
    "            new Person(\"Charlie\", 35)\n",
    "        };\n",
    "\n",
    "        // 使用 Lambda 表达式定义 Comparator\n",
    "        Arrays.sort(people, (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));\n",
    "\n",
    "        // 打印排序后的数组\n",
    "        System.out.println(\"Sorted array by age using anonymous inner class: \" );\n",
    "        for(Person temp:people){\n",
    "            System.out.println(temp.toString());\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "Main.main(new String[] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Comparator 的应用场景\n",
    "### 应用于 List\n",
    "在 List 中，可以使用 Collections.sort(List<T> list, Comparator<? super T> c) 方法来对列表进行排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sorted list by age using Lambda: \n",
      "Person{name='Bob', age=25}\n",
      "Person{name='Alice', age=30}\n",
      "Person{name='Charlie', age=35}\n"
     ]
    }
   ],
   "source": [
    "import java.util.ArrayList;\n",
    "import java.util.Collections;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        ArrayList<Person> people = new ArrayList<>();\n",
    "        people.add(new Person(\"Alice\", 30));\n",
    "        people.add(new Person(\"Bob\", 25));\n",
    "        people.add(new Person(\"Charlie\", 35));\n",
    "\n",
    "        // 使用 Lambda 表达式简化代码\n",
    "        Collections.sort(people, (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));\n",
    "\n",
    "        // 打印排序后的列表\n",
    "        System.out.println(\"Sorted list by age using Lambda: \" );\n",
    "        for(Person temp:people){\n",
    "            System.out.println(temp.toString());\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "\n",
    "Main.main(new String[] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 应用于 Set\n",
    "虽然 Set 本身不支持排序，但 TreeSet 类实现了 SortedSet 接口，允许使用 Comparator 来控制元素的排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sorted set by age: \n",
      "Person{name='Bob', age=25}\n",
      "Person{name='Alice', age=30}\n",
      "Person{name='Charlie', age=35}\n"
     ]
    }
   ],
   "source": [
    "import java.util.TreeSet;\n",
    "import java.util.Comparator;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        TreeSet<Person> people = new TreeSet<>(new Comparator<Person>() {\n",
    "            @Override\n",
    "            public int compare(Person p1, Person p2) {\n",
    "                return Integer.compare(p1.getAge(), p2.getAge());\n",
    "            }\n",
    "        });\n",
    "\n",
    "        people.add(new Person(\"Alice\", 30));\n",
    "        people.add(new Person(\"Bob\", 25));\n",
    "        people.add(new Person(\"Charlie\", 35));\n",
    "\n",
    "        // 打印排序后的集合\n",
    "        System.out.println(\"Sorted set by age: \" );\n",
    "        for(Person temp:people){\n",
    "            System.out.println(temp.toString());\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "Main.main(new String[] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 应用于 Map\n",
    "Map 本身不支持排序，但如果需要对 Map 的键或值进行排序，可以使用 TreeMap 并提供一个 Comparator。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sorted map by key length: \n",
      "apple: 1\n",
      "banana: 3\n"
     ]
    }
   ],
   "source": [
    "import java.util.TreeMap;\n",
    "import java.util.Comparator;\n",
    "\n",
    "public class Main {\n",
    "    public static void main(String[] args) {\n",
    "        TreeMap<String, Integer> map = new TreeMap<>(new Comparator<String>() {\n",
    "            @Override\n",
    "            public int compare(String s1, String s2) {\n",
    "                return s1.length() - s2.length();\n",
    "            }\n",
    "        });\n",
    "\n",
    "        map.put(\"apple\", 1);\n",
    "        map.put(\"banana\", 2);\n",
    "        map.put(\"cherry\", 3);\n",
    "\n",
    "        // 打印排序后的映射\n",
    "        System.out.println(\"Sorted map by key length: \" );\n",
    "        // 遍历 Map 的键值对 \n",
    "        // 因为 TreeMap 是基于红黑树实现的，它保证了键的有序性，但同时也会自动去除重复的键。因此后来插入的键值对将会覆盖前面的键值对\n",
    "        for (Map.Entry<String, Integer> entry : map.entrySet()) {\n",
    "            System.out.println(entry.getKey() + \": \" + entry.getValue());\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "Main.main(new String[] {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Comparator 接口在 Java 中提供了强大的排序功能，允许开发者自定义对象的比较逻辑。无论是集合还是数组，都可以通过实现 Comparator 接口来控制排序顺序。掌握 Comparator 的使用方法，对于开发高质量的应用程序至关重要。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "17.0.11+7-LTS-207"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
